package common

import (
	"context"
	"encoding/json"
	"github.com/gorhill/cronexpr"
	"strings"
	"time"
)

type (
	Job struct {
		Name     string `json:"name"`
		Command  string `json:"command"`
		CronExpr string `json:"cronExpr"`
	}

	// 任务调度计划
	JobSchedulerPlan struct {
		Job      *Job                 // 需要调度的任务信息
		Expr     *cronexpr.Expression // 解析好的cronexpr表达式
		NextTime time.Time            // 任务的下次调度时间
	}

	// 任务执行状态
	JobExcuteInfo struct {
		Job        *Job
		PlanTime   time.Time       // 理论调度时间
		RealTime   time.Time       // 真实调度时间
		CancelCtx  context.Context // 用于取消任务
		CancelFunc context.CancelFunc
	}

	// 任务的执行结果
	JobExcuteResult struct {
		ExcuteInfo *JobExcuteInfo
		Output     []byte    // 脚本输出的结果
		Err        error     // 脚本的错误原因
		StartTime  time.Time // 脚本启动时间
		EndTime    time.Time // 脚本结束时间
	}

	// 任务变化事件，有2种
	JobEvent struct {
		EventType int // SAVE，DELETE
		Job       *Job
	}

	JobLog struct {
		JobName      string `json:"jobName" bson:"jobName""`
		Command      string `json:"command" bson:"command"`
		Err          string `json:"err" bson:"err"`
		Output       string `json:"output" bson:"output"`
		PlanTime     int64  `json:"planTime" bson:"planTime"` // 任务 计划调度时间
		ScheduleTime int64  `json:"scheduleTime" bson:"scheduleTime"` // 任务调度时间
		StartTime    int64  `json:"startTime" bson:"startTime"` // 任务开始时间
		EndTime      int64  `json:"endTime" bson:"endTime"` // 任务执行结束时间
	}

	// 批量日志
	LogBatch struct {
		Logs []interface{} // 多条日志
	}

	// ---------------------- >>> mongodb查询条件定义 ---------------------------
	JobLogFilter struct {
		JobName string `bson:"jobName"`
	}
	SortLogByStartTime struct {
		SortOrder int `bson:"startTime"` // {startTime:-1}
	}
	// ---------------------- <<< mongodb查询条件定义 ---------------------------

	Response struct {
		Code int         `json:"code"`
		Msg  string      `json:"msg"`
		Data interface{} `json:"data"`
	}
)

// http接口应答
func BuildResponse(code int, msg string, data interface{}) (resp []byte, err error) {
	response := Response{
		Code: code,
		Msg:  msg,
		Data: data,
	}
	return json.Marshal(response)
}

// 反序列化job
func UnpackJob(value []byte) (ret *Job, err error) {
	var (
		job = &Job{}
	)
	if err = json.Unmarshal(value, job); err != nil {
		return
	}
	ret = job
	return
}

// 从etcd的key中提取任务名
func ExtractJobName(jobKey string) (string) {
	return strings.TrimPrefix(jobKey, JOB_SAVE_DIR)
}
func ExtractKillerName(killerKey string) (string) {
	return strings.TrimPrefix(killerKey, JOB_KILLER_DIR)
}
func ExtractWokerIP(regKey string) (string) {
	return strings.TrimPrefix(regKey, JOB_WORKER_DIR)
}

func BuildJobEvent(eventType int, job *Job) (jobEvent *JobEvent) {
	return &JobEvent{
		EventType: eventType,
		Job:       job,
	}
}

// 
func BuildJobSchedulePlan(job *Job) (jobSchedulerPlan *JobSchedulerPlan, err error) {
	var (
		expr *cronexpr.Expression
	)

	if expr, err = cronexpr.Parse(job.CronExpr); err != nil {
		return
	}

	jobSchedulerPlan = &JobSchedulerPlan{
		Job:      job,
		Expr:     expr,
		NextTime: expr.Next(time.Now()),
	}
	return
}

func BuildJobExcuteInfo(plan *JobSchedulerPlan) (jobExcuteInfo *JobExcuteInfo) {
	jobExcuteInfo = &JobExcuteInfo{
		Job:      plan.Job,
		PlanTime: plan.NextTime, // 计算调度时间
		RealTime: time.Now(),    // 真实调度时间
	}
	jobExcuteInfo.CancelCtx, jobExcuteInfo.CancelFunc = context.WithCancel(context.TODO())
	return
}
